package com.kirkkt.javatests.arithmetic;

import com.kirkkt.java.arithmetic.Arithmetic;

public class ArithmeticTest {
    public static void main(String[] args) {
        new ArithmeticTest().run();
    }

    public static void assertThat(boolean expression, String message) {
        if (expression) {
            System.out.println("assertion passed");
        } else {
            System.out.println("ASSERTION ERROR: " + message);
            System.exit(1);
        }
    }

    private void run() {
        testCalculate();
        testGetOperatorIndex();
        testGetInnerExpression();
        testBuildTree();
    }

    private void testCalculate() {
        // basic calculations
        {
            Arithmetic arithmetic = new Arithmetic() {
                public boolean isOperator(String input) {
                    return true;
                }
            };
            assertThat(arithmetic.calculate("+", 10, 20) == 30, "addition");
            assertThat(arithmetic.calculate("-", 10, 20) == -10, "subtraction");
            assertThat(arithmetic.calculate("*", 10, 20) == 200, "multiplication");
            assertThat(arithmetic.calculate("/", 10, 20) == .5, "division");

            try {
                arithmetic.calculate("!", 10, 20);
                assertThat(false, "should not reach here");
            } catch (Exception exception) {
                assertThat(exception instanceof RuntimeException, "it's a runtime exception");
                assertThat(
                    exception.getMessage().equals("unable to calculate based on operator: !"),
                    "it says the right error message"
                );
            }
        }

        // unrecognized operator
        {
            Arithmetic arithmetic = new Arithmetic() {
                public boolean isOperator(String input) {
                    return false;
                }
            };

            try {
                arithmetic.calculate("!", 10, 20);
                assertThat(false, "should not reach here");
            } catch (Exception exception) {
                assertThat(exception instanceof RuntimeException, "it's a runtime exception");
                assertThat(
                    exception.getMessage().equals("illegal operator: !"),
                    "it says the right error message"
                );
            }
        }
    }

    private void testGetOperatorIndex() {
        Arithmetic arithmetic = new Arithmetic() {
            public boolean isOperator(char input) {
                return input == '!';
            }
        };
        assertThat(arithmetic.getOperatorIndex("123") == -1, "no operator");
        assertThat(arithmetic.getOperatorIndex("12!3") == 2, "no parenthesis");
        assertThat(arithmetic.getOperatorIndex("(1!2)!3") == 5, "parenthesis before operator");
        assertThat(arithmetic.getOperatorIndex("4!(1!2)") == 1, "parenthesis after operator");
        assertThat(arithmetic.getOperatorIndex("(4!(1!2)!3)") == -1, "parenthesis contains everything");
        assertThat(arithmetic.getOperatorIndex("(4!(1!2)!3)!(5!6)") == 11, "2 sets of parenthesis");
    }

    private void testGetInnerExpression() {
        Arithmetic arithmetic = new Arithmetic();
        assertThat(arithmetic.getInnerExpression("123").equals("123"), "no leading or trailing parenthesis");
        assertThat(arithmetic.getInnerExpression("(123").equals("(123"), "no trailing parenthesis");
        assertThat(arithmetic.getInnerExpression("123)").equals("123)"), "no leading parenthesis");
        assertThat(arithmetic.getInnerExpression("(123)").equals("123"), "with leading and trailing parenthesis");
    }

    private void testBuildTree() {
    }
}
